﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace Maydew.Windows.Forms.Controls.FlexiCell
{
    public partial class FlexiCellControl : Control
    {
        #region " 私有变量 "
        /// <summary>
        /// 获取单元格集合。
        /// </summary>
        private CellCollection _cells;
        /// <summary>
        /// 获取行集合。
        /// </summary>
        private RowHeaderCollection _rows;
        /// <summary>
        /// 获取列集合。
        /// </summary>
        private ColumnHeaderCollection _columns;
        /// <summary>
        /// 获取边框颜色。
        /// </summary>
        private Color _borderColor;
        /// <summary>
        /// 获取右上角单元格。
        /// </summary>
        private ColumnHeader _header;
        /// <summary>
        /// 水平滚动条。
        /// </summary>
        private HScrollBar _hScrollBar;
        /// <summary>
        /// 垂值滚动条。
        /// </summary>
        private VScrollBar _vScrollBar;
        /// <summary>
        /// 用于填充右下角滚动条空白。
        /// </summary>
        private Label _label;
        /// <summary>
        /// 鼠标按下状态。
        /// </summary>
        private bool _mousePressed;
        #endregion

        #region " 构造函数 "
        /// <summary>
        /// 初始化  类的新实例。
        /// </summary>
        public FlexiCellControl()
        {
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.Selectable, true);

            _borderColor = Color.FromArgb(158, 182, 206);

            int size = 17;

            Width = 300;
            Height = 300;

            _hScrollBar = new HScrollBar();
            size = _hScrollBar.Height;
            _hScrollBar.Left = 1;
            _hScrollBar.Top = Height - size-1;
            _hScrollBar.Width = Width - size-1;
            _hScrollBar.Height = size;
            _hScrollBar.Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right;
            _hScrollBar.Scroll += new ScrollEventHandler(_hScrollBar_Scroll);
            Controls.Add(_hScrollBar);

            _vScrollBar = new VScrollBar();
            _vScrollBar.Left = Width - size-1;
            _vScrollBar.Top = 1;
            _vScrollBar.Width = size;
            _vScrollBar.Height = Height - size-1;
            _vScrollBar.Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;
            _vScrollBar.Scroll += new ScrollEventHandler(_vScrollBar_Scroll);
            Controls.Add(_vScrollBar);

            _label = new Label();
            _label.Left = _vScrollBar.Left;
            _label.Top = _hScrollBar.Top;
            _label.Size = new System.Drawing.Size(size, size);
            _label.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
            Controls.Add(_label);

            _header = new ColumnHeader();
            _header.Canvas = this;
            _header.Width = 40;
            _header.Height = 21;
            _header.Left = 0;
            _header.Top = 0;

            _cells = new CellCollection(this);
            _cells.Changed += new CollectionChangeEventHandler(_cells_Changed);
            _rows = new RowHeaderCollection(this);
            _rows.Changed += new CollectionChangeEventHandler(_rows_Changed);
            _columns = new ColumnHeaderCollection(this);
            _columns.Changed += new CollectionChangeEventHandler(_columns_Changed);

            _focusedCells = new List<Cell>();
            _fullFocusedRows = new List<RowHeader>();
            _fullFocusedColumns = new List<ColumnHeader>();

            BeginUpdate();

            int rows = 60;
            int columns = 26;
            for (int i = 0; i < rows; i++)
            {
                AddRow();
            }
            for (int i = 0; i < columns; i++)
            {
                AddColumn();
            }

            EndUpdate();
        }
        #endregion

        #region " 滚动条 "
        /// <summary>
        /// 垂直滚动条滚动时发生。
        /// </summary>
        /// <param name="sender">事件对象。</param>
        /// <param name="e">事件参数。</param>
        private void _vScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            int y = _header.Bounds.Bottom;
            for (int r = e.NewValue - 1; r >= 0; r--)
            {
                y -= _rows[r].Height;
                _rows[r].Top = y;
                _rows[r].Visible = false;
            }
            y = _header.Bounds.Bottom;
            for (int i = e.NewValue; i < RowCount; i++)
            {
                _rows[i].Visible = true;
                _rows[i].Top = y;
                y = _rows[i].Bounds.Bottom;
            }
            Rectangle headerBound = _header.Bounds;
            Rectangle rect = new Rectangle(
                headerBound.Right, headerBound.Bottom,
                Width - headerBound.Width, Height - headerBound.Height);
            for (int r = 0; r < RowCount; r++)
            {
                List<Cell> cells = _cells.GetRow(r);
                for (int i = 0; i < cells.Count; i++)
                {
                    bool visibile = (r >= e.NewValue);
                    if (visibile)
                    {
                        if (cells[i].Merged &&
                            cells[i].MergedCells.Count==0)
                        {
                            visibile = false;
                        }
                    }
                    else if(cells[i].Merged && cells[i].MergedCells.Count>0)
                    {
                        if (rect.IntersectsWith(cells[i].Bounds)) visibile = true;
                    }
                    cells[i].Top = _rows[r].Top;
                    cells[i].Visible = visibile;
                }
            }
            if (e.Type == ScrollEventType.SmallIncrement && 
                ValidateAddRow())
            {
                ResetScrollBar();
            }
            else
            {
                base.Refresh();
            }
        }
        /// <summary>
        /// 水平滚动条滚动时发生。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _hScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            int x = _header.Bounds.Right;
            for (int i = e.NewValue - 1; i >= 0; i--)
            {
                x -= _columns[i].Width;
                _columns[i].Left = x;
                _columns[i].Visible = false;
            }
            x = _header.Bounds.Right;
            for (int i = e.NewValue; i < ColumnCount; i++)
            {
                _columns[i].Visible = true;
                _columns[i].Left = x;
                x = _columns[i].Bounds.Right;
            }
            Rectangle headerBound = _header.Bounds;
            Rectangle rect = new Rectangle(
                headerBound.Right, headerBound.Bottom,
                Width - headerBound.Width, Height - headerBound.Height);
            for (int i = 0; i < ColumnCount; i++)
            {
                List<Cell> cells = _cells.GetColumn(_columns[i].ColumnName);
                for (int j = 0; j < cells.Count; j++)
                {
                    bool visibile = (i >= e.NewValue);
                    if (visibile)
                    {
                        if (cells[j].Merged &&
                            cells[j].MergedCells.Count == 0)
                        {
                            visibile = false;
                        }
                    }
                    else if (cells[j].Merged && cells[j].MergedCells.Count > 0)
                    {
                        if (rect.IntersectsWith(cells[j].Bounds)) visibile = true;
                    }
                    cells[j].Visible = visibile;
                    cells[j].Left = _columns[i].Left;
                }
            }

            if (e.Type == ScrollEventType.SmallIncrement &&
                ValidateAddColumn())
            {
                ResetScrollBar();
            }
            else
            {
                base.Refresh();
            }
        }
        /// <summary>
        /// 验证添加新行。
        /// </summary>
        /// <returns></returns>
        private bool ValidateAddRow()
        {
            bool result = false;
            while (_rows[RowCount - 1].Bounds.Bottom < Height)
            {
                AddRow();
                result = true;
            }
            return result;
        }
        /// <summary>
        /// 验证添加新列。
        /// </summary>
        /// <returns></returns>
        private bool ValidateAddColumn()
        {
            bool result = false;
            while (_columns[ColumnCount - 1].Bounds.Right < Width)
            {
                AddColumn();
                result = true;
            }
            return result;
        }
        /// <summary>
        /// 设置滚动条滚动参数。
        /// </summary>
        private void ResetScrollBar()
        {
            if (_rows == null || _columns == null ||
                _rows.Count == 0 || _columns.Count == 0) return;

            int w = 0;
            int columnIndex = ColumnCount;
            for (int i = ColumnCount-1; i >=0; i--)
            {
                w += _columns[i].Width;
                if (w > Width)
                {
                    columnIndex = i;
                    break;
                }
            }
            columnIndex += 10;
            _hScrollBar.Minimum = 0;
            _hScrollBar.Maximum = columnIndex;

            int h = 0;
            int rowIndex = RowCount;
            for (int i =RowCount-1; i >=0; i--)
            {
                h += _rows[i].Height;
                if (h > Height)
                {
                    rowIndex = i;
                    break;
                }
            }
            rowIndex += 11;
            _vScrollBar.Minimum = 0;
            _vScrollBar.Maximum = rowIndex;

            base.Refresh();
        }
        /// <summary>
        /// 当鼠标滚轮滚动时发生。
        /// </summary>
        /// <param name="e">事件参数。</param>
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            int value = _vScrollBar.Value;
            value -= Math.Sign(e.Delta);
            if (value >= _vScrollBar.Minimum && value <= _vScrollBar.Maximum)
            {
                ScrollEventArgs args = new ScrollEventArgs(ScrollEventType.SmallIncrement, _vScrollBar.Value, value);
                _vScrollBar.Value = value;
                _vScrollBar_Scroll(_vScrollBar, args);
            }
            base.OnMouseWheel(e);
        }
        #endregion

        #region " 属性 "
        /// <summary>
        /// 获取单元格集合。
        /// </summary>
        public CellCollection Cells
        {
            get
            {
                return _cells;
            }
        }
        /// <summary>
        /// 获取行集合。
        /// </summary>
        public RowHeaderCollection Rows
        {
            get
            {
                return _rows;
            }
        }
        /// <summary>
        /// 获取列集合。
        /// </summary>
        public ColumnHeaderCollection Columns
        {
            get
            {
                return _columns;
            }
        }
        /// <summary>
        /// 获取或设置边框颜色。
        /// </summary>
        public Color BorderColor
        {
            get
            {
                return _borderColor;
            }
            set
            {
                if (_borderColor != value)
                {
                    _borderColor = value;
                    base.Refresh();
                }
            }
        }
        #endregion

        #region " 友元属性 "
        /// <summary>
        /// 获取行数。
        /// </summary>
        protected int RowCount
        {
            get { return _rows.Count; }
        }
        /// <summary>
        /// 获取列数。
        /// </summary>
        protected int ColumnCount
        {
            get { return _columns.Count; }
        }
        #endregion

        #region " Row "
        /// <summary>
        /// 添加新行。
        /// </summary>
        public void AddRow()
        {
            InsertRow(RowCount);
        }
        /// <summary>
        /// 插入新行。
        /// </summary>
        /// <param name="index">插入位置。</param>
        public void InsertRow(int index)
        {
            int height = 21;
            
            for (int i = index; i < RowCount; i++)
            {
                List<Cell> cells = _cells.GetRow(i);
                for (int j = 0; j < cells.Count; j++)
                {
                    cells[j].RowIndex += 1;
                    cells[j].Top += height;
                }
            }

            for (int i = index; i < RowCount; i++)
            {
                _rows[i].RowIndex += 1;
                _rows[i].Top += height;
            }

            RowHeader row = new RowHeader();
            row.RowIndex = index;
            row.Caption = string.Format("{0}", index+1);
            row.Width = _header.Width;
            row.Height = height;
            row.Left = 0;
            row.Top = GetTop(index);
            _rows.Insert(index, row);

            for (int i = 0; i < ColumnCount; i++)
            {
                Cell cell = new Cell();
                cell.RowIndex = index;
                cell.ColumnName = _columns[i].ColumnName;
                cell.Width = _columns[cell.ColumnName].Width;
                cell.Height = _rows[cell.RowIndex].Height;
                cell.Left = _columns[cell.ColumnName].Left;
                cell.Top = _rows[cell.RowIndex].Top;

                _cells.Add(cell);
            }

            ResetScrollBar();
        }
        #endregion

        #region " Column "
        /// <summary>
        /// 添加新列。
        /// </summary>
        public void AddColumn()
        {
            InsertColumn(ColumnCount);
        }
        /// <summary>
        /// 插入新列。
        /// </summary>
        /// <param name="index">插入位置。</param>
        public void InsertColumn(int index)
        {
            int width = 100;

            for (int i = index; i < ColumnCount; i++)
            {
                List<Cell> cells = _cells.GetColumn(_columns[i].ColumnName);
                for (int j = 0; j < cells.Count; j++)
                {
                    cells[j].ColumnName = GetColumnName(i + 1);
                    cells[j].Left += width;
                }
            }

            for (int i = index; i < ColumnCount; i++)
            {
                _columns[i].ColumnName = GetColumnName(i + 1);
                _columns[i].Left += width;
            }

            ColumnHeader column = new ColumnHeader();
            column.ColumnName = GetColumnName(index);
            column.Caption = column.ColumnName;
            column.Width = width;
            column.Height = _header.Height;
            column.Left = GetLeft(index);
            column.Top = 0;
            _columns.Insert(index, column);

            for (int i = 0; i < RowCount; i++)
            {
                Cell cell = new Cell();
                cell.RowIndex = i;
                cell.ColumnName = column.ColumnName;
                cell.Width = _columns[cell.ColumnName].Width;
                cell.Height = _rows[cell.RowIndex].Height;
                cell.Left = _columns[cell.ColumnName].Left;
                cell.Top = _rows[cell.RowIndex].Top;

                _cells.Add(cell);
            }

            ResetScrollBar();
        }
        /// <summary>
        /// 获取列名。
        /// </summary>
        /// <param name="index">列位置。</param>
        /// <returns>返回默认列名。</returns>
        private string GetColumnName(int index)
        {
            int last = index % 26 + 65;
            int i = index / 26;
            if (i == 0)
                return string.Format("{0}", (char)last);
            else
                return string.Format("{1}{0}", (char)last, GetColumnName(i - 1));
        }
        #endregion

        #region " 获取单元格位置 "
        /// <summary>
        /// 获取单元格上侧位置。
        /// </summary>
        /// <param name="rowIndex">行位置。</param>
        /// <returns>返回单元格上侧位置。</returns>
        private int GetTop(int rowIndex)
        {
            RowHeader row = null;
            if (rowIndex - 1 >= 0) row = _rows[rowIndex - 1];
            int top = 0;
            if (row == null)
            {
                top = _header.Bounds.Bottom;
            }
            else
            {
                top = row.Bounds.Bottom;
            }
            return top;
        }
        /// <summary>
        /// 获取单元格左侧位置。
        /// </summary>
        /// <param name="columnIndex">列位置。</param>
        /// <returns>返回单元格左侧位置。</returns>
        private int GetLeft(int columnIndex)
        {
            ColumnHeader column = null;
            if (columnIndex - 1 >= 0) column = _columns[columnIndex - 1];
            int left = 0;
            if (column == null)
            {
                left = _header.Bounds.Right;
            }
            else
            {
                left = column.Bounds.Right;
            }
            return left;
        }
        #endregion

        #region " 绘制表格 "
        /// <summary>
        /// 绘制控件。
        /// </summary>
        /// <param name="e">绘图参数。</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            Rectangle bounds = new Rectangle(0, 0, Width, Height);
            foreach (Cell cell in _cells)
            {
                if (bounds.IntersectsWith(cell.Bounds))
                {
                    cell.Painting(e);
                }
            }
            
            foreach (ColumnHeader column in _columns)
            {
                if (!column.Focused && !column.FullColumnFocused)
                {
                    column.Painting(e);
                }
            }
            foreach (RowHeader row in _rows)
            {
                if (!row.Focused && !row.FullRowFocused)
                {
                    row.Painting(e);
                }
            }

            foreach (ColumnHeader column in _fullFocusedColumns)
            {
                column.Painting(e);
            }
            foreach (RowHeader row in _fullFocusedRows)
            {
                row.Painting(e);
            }

            _header.Painting(e);

            DrawingBorder(e);

            base.OnPaint(e);
        }
        /// <summary>
        /// 绘制边框。
        /// </summary>
        /// <param name="e">绘图参数。</param>
        protected virtual void DrawingBorder(PaintEventArgs e)
        {
            using (Pen pen = new Pen(_borderColor))
            {
                Rectangle rect = new Rectangle(0, 0, Width - 1, Height - 1);
                e.Graphics.DrawRectangle(pen, rect);
            }
        }
        #endregion

        #region " 友元方法--基类 "
        /// <summary>
        /// 当控件尺寸改变时发生。
        /// </summary>
        /// <param name="e">事件参数。</param>
        protected override void OnResize(EventArgs e)
        {
            BeginUpdate();
            ResetScrollBar();
            EndUpdate();
            base.OnResize(e);
        }
        /// <summary>
        /// 当鼠标按下时发生。
        /// </summary>
        /// <param name="e">事件参数。</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            this.Focus();

            base.OnMouseDown(e);
        }
        #endregion

        private bool _updating;

        public void BeginUpdate()
        {
            _updating = true;
        }

        public void EndUpdate()
        {
            base.Refresh();
            _updating = false;
        }

        public override void Refresh()
        {
            if (!_updating) base.Refresh();
        }

        //internal void Redraw()
        //{
        //    if (!_updating) base.Refresh();
        //}
    }
}
